package com.fanshuai.queue.blocking;

import com.fanshuai.queue.Queue;

public class ArrayBlockingQueue<E> implements Queue<E> {

    private E[] array;
    private int head;
    private int tail;
    private int capacity;

    /**
     * 队列满时的同步器
     */
    private final Object fullLock = new Object();
    /**
     * 队列空时的同步器
     */
    private final Object emptyLock = new Object();
    /**
     * 数据操作同步
     */
    private final Object dataLock = new Object();

    public ArrayBlockingQueue(int capacity) {
        array = (E[]) new Object[capacity + 1];
        head = 0;
        tail = 0;
        this.capacity = capacity + 1;
    }

    @Override
    public int size() {
        if (tail >= head) {
            return tail - head;
        } else {
            int empty = head - tail;
            return capacity - empty;
        }
    }

    @Override
    public boolean isEmpty() {
        return head == tail;
    }

    @Override
    public boolean isFull() {
        return (tail + 1) % capacity == head;
    }

    @Override
    public void enqueue(E data) {
        //队列满时阻塞
        while (isFull()) {
            synchronized (fullLock) {
                try {
                    fullLock.wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        synchronized (dataLock) {
            array[tail] = data;
            tail = (tail + 1) % capacity;
        }

        //唤醒等待队列非空的线程
        synchronized (emptyLock) {
            emptyLock.notifyAll();
        }
    }

    @Override
    public E dequeue() {
        while (isEmpty()) {
            synchronized (emptyLock) {
                try {
                    emptyLock.wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        E data = null;
        synchronized (dataLock) {
            data = array[head];
            array[head] = null;
            head = (head + 1) % capacity;
        }

        //唤醒等待队列非满的线程
        synchronized (fullLock) {
            fullLock.notifyAll();
        }

        return data;
    }

    @Override
    public E peek() {
        return array[head];
    }
}
